#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <sys/time.h>
#include <sys/types.h>

#include <pthread.h>

#ifdef _WIN32_WINNT
    #include <ws2tcpip.h>
    #include <winsock2.h>
#else
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/un.h>
    #include <netdb.h>
#endif

#include "hj212_client_ops.h"

#define HJ_LOG_TAG  "hj212.port"        // 日志标签
#define HJ_LOG_LVL HJ_DBG_INFO          // 日志等级
#include "hjdebug.h"


struct simulator_hj212_client;
struct simulator_time_interval_source
{
    struct hj212_datasource parent;
    int type;
    int last_time;
    int interval;

    struct simulator_hj212_client *client;
};
struct simulator_time_section_source
{
    struct hj212_datasource parent;
    int type;

    time_t begin_time;
    int interval;

    int begin;
    int end;

    struct simulator_hj212_client *client;
};
struct simulator_hj212_client
{
    struct hj212_client parent;

    int sockfd;
    int isconnect;

    pthread_t recv_pid;
    struct gen_blk_queue recvbuffer;
    char tmp[2048];

    pthread_mutex_t lock;

    char syscode[HJ212_SYSCODE_MAX_LEN];
    char access_pwd[HJ212_ACCESS_PWD_MAX_LEN];
    char client_mn[HJ212_MN_MAX_LEN];
    int protocol;
    int rtd_cycle;
    int min_cycle;
    int heartbeat_cycle;
    int maxret;
    int send_inter;
    int stream_timeout;
    struct simulator_time_interval_source datasource[HJ212_MSG_TYPE_NUM];
};

static void *simulator_socket_recv_entry(void *param);

static int simulator_time_interval_source_is_empty(struct hj212_datasource *source);
static int simulator_time_interval_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg);
static int simulator_time_section_source_is_empty(struct hj212_datasource *source);
static int simulator_time_section_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg);

static int simulator_command(struct hj212_client *client, int cmd, void *args);
static time_t simulator_current_timestamp(void);
static struct timeval simulator_current_subsec(void);
static void simulator_lock(struct hj212_client *client);
static int simulator_trylock(struct hj212_client *client);
static void simulator_unlock(struct hj212_client *client);
static void *simulator_malloc(size_t size);
static void *simulator_calloc(unsigned int num, size_t size);
static void simulator_free(void *ptr);
static int simulator_dev_open(struct hj212_client *client, int flag);
static int simulator_dev_close(struct hj212_client *client);
static int simulator_dev_state(struct hj212_client *client);
static int simulator_dev_recv(struct hj212_client *client, uint8_t *buffer, int len, int timeout);
static int simulator_dev_send(struct hj212_client *client, const uint8_t *buffer, int len);
static struct hj212_datasource *simulator_get_data_source(struct hj212_client *client, int type);
static struct hj212_datasource *simulator_create_hisdata_source(struct hj212_client *client, int type, time_t begin, time_t end);
static void simulator_delete_data_source(struct hj212_client *client, struct hj212_datasource *source);

const static struct hj212_client_ops simulator_hj212_client_ops =
{
    .command = simulator_command,
    .current_timestamp = simulator_current_timestamp,
    .current_subsec  = simulator_current_subsec,
    .lock = simulator_lock,
    .trylock = simulator_trylock,
    .unlock = simulator_unlock,
    .malloc = simulator_malloc,
    .calloc = simulator_calloc,
    .free = simulator_free,
    .dev_open = simulator_dev_open,
    .dev_close = simulator_dev_close,
    .dev_state = simulator_dev_state,
    .dev_recv = simulator_dev_recv,
    .dev_send = simulator_dev_send,
    .get_data_source = simulator_get_data_source,
    .create_hisdata_source = simulator_create_hisdata_source,
    .delete_data_source = simulator_delete_data_source,
};

static void socket_reset(struct simulator_hj212_client *client)
{
    simulator_dev_close(&client->parent);
    simulator_dev_open(&client->parent, 0);
}

static void *simulator_socket_recv_entry(void *param)
{
    struct simulator_hj212_client *client = param;
    while (1)
    {
        if (client->isconnect)
        {
            int len = recv(client->sockfd, client->tmp, sizeof(client->tmp), 0);
            if (len > 0)
            {
                simulator_lock(&client->parent);
                gen_blk_queue_push_force(&client->recvbuffer, (uint8_t *)client->tmp, len);
                simulator_unlock(&client->parent);
            }
            else
            {
                simulator_lock(&client->parent);
                socket_reset(client);
                simulator_unlock(&client->parent);
            }
        }
        Sleep(50);
    }
    return NULL;
}
struct hj212_client *hj212_simulator_create(int id)
{
    struct simulator_hj212_client *client = simulator_calloc(1, sizeof(struct simulator_hj212_client));

    HJ_LOG_I("hj212_simulator_create:id=%d", id);

    strcpy(client->syscode, "32");
    strcpy(client->access_pwd, "123456");
    strcpy(client->client_mn, "simulator");
    client->protocol = HJ212_PROTOCOL_2017;
    client->rtd_cycle = 30;
    client->min_cycle = 60 * 2;
    client->heartbeat_cycle = 60 * 2;
    client->maxret = 5;
    client->send_inter = 500;
    client->stream_timeout = 2;

    client->isconnect = 0;

    void *recvbuffer = simulator_calloc(1, 1024 * 10);
    if (!recvbuffer)
    {
        simulator_free(client);
        HJ_LOG_I("#%d socket: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) result = %d", client->parent.id, client->sockfd);
        return NULL;
    }
    gen_blk_queue_init(&client->recvbuffer, recvbuffer, 1, 1024 * 10);

    pthread_mutex_init(&client->lock, NULL);

    if (hj212_client_init(&client->parent, id, client->protocol, &simulator_hj212_client_ops) < 0)
    {
        pthread_mutex_destroy(&client->lock);
        pthread_detach(client->recv_pid);
        simulator_free(client);
        return NULL;
    }
    static const int hj212_type_interval[HJ212_MSG_TYPE_NUM] =
    {
        [HJ212_MSG_TYPE_RTD]    = 30,
        [HJ212_MSG_TYPE_MIN]    = 60 * 2,
        [HJ212_MSG_TYPE_HOUR]   = 60 * 60,
        [HJ212_MSG_TYPE_DAY]    = 60 * 60 * 24,
    };
    for (int i = 0; i < HJ212_MSG_TYPE_NUM; i++)
    {
        client->datasource[i].type = i;
        client->datasource[i].interval = hj212_type_interval[i];
        client->datasource[i].last_time = simulator_current_timestamp() /
                                          client->datasource[i].interval *
                                          client->datasource[i].interval;
        client->datasource[i].parent.is_empty = simulator_time_interval_source_is_empty;
        client->datasource[i].parent.next = simulator_time_interval_source_next;

        client->datasource[i].client = client;
    }

    pthread_create(&client->recv_pid, NULL, simulator_socket_recv_entry, client);

    return (struct hj212_client *)client;
}

static int simulator_command(struct hj212_client *client, int cmd, void *args)
{
    int result = 0;
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    this = this;
    switch (cmd)
    {
    case GET_HJ212_SYS_CODE:
        memcpy(args, this->syscode, HJ212_SYSCODE_MAX_LEN);
        break;
    case GET_HJ212_ACCESS_PWD:
        memcpy(args, this->access_pwd, HJ212_ACCESS_PWD_MAX_LEN);
        break;
    case GET_HJ212_CLIENT_MN:
        memcpy(args, this->client_mn, HJ212_MN_MAX_LEN);
        break;
    case GET_HJ212_PROTOCOL:
        *((int *)args) = this->protocol;
        break;
    case GET_HJ212_RTD_CYCLE:
        *((int *)args) = this->rtd_cycle;
        break;
    case GET_HJ212_MIN_CYCLE:
        *((int *)args) = this->min_cycle;
        break;
    case GET_HJ212_HEARTBEAT_CYCLE:
        *((int *)args) = this->heartbeat_cycle;
        break;
    case GET_HJ212_MAXRET:
        *((int *)args) = this->maxret;
        break;
    case GET_HJ212_SEND_INTER:
        *((int *)args) = this->send_inter;
        break;
    case GET_HJ212_STREAM_TIMEOUT:
        *((int *)args) = this->stream_timeout;
        break;
    case SET_HJ212_SYS_CODE:
        memcpy(this->syscode, args, HJ212_SYSCODE_MAX_LEN);
        break;
    case SET_HJ212_ACCESS_PWD:
        memcpy(this->access_pwd, args, HJ212_ACCESS_PWD_MAX_LEN);
        break;
    case SET_HJ212_CLIENT_MN:
        memcpy(this->client_mn, args, HJ212_MN_MAX_LEN);
        break;
    case SET_HJ212_PROTOCOL:
        this->protocol = *((int *)args);
        break;
    case SET_HJ212_RTD_CYCLE:
        this->rtd_cycle = *((int *)args);
        break;
    case SET_HJ212_MIN_CYCLE:
        this->min_cycle = *((int *)args);
        break;
    case SET_HJ212_HEARTBEAT_CYCLE:
        this->heartbeat_cycle = *((int *)args);
        break;
    case SET_HJ212_MAXRET:
        this->maxret = *((int *)args);
        break;
    case SET_HJ212_SEND_INTER:
        this->send_inter = *((int *)args);
        break;
    case SET_HJ212_STREAM_TIMEOUT:
        this->stream_timeout = *((int *)args);
        break;
    default:
        result = -1;
        break;
    }
    HJ_LOG_D("#%d-command=%d", client->id, cmd);
    return result;
}
static time_t simulator_current_timestamp(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return time.tv_sec;
}
static struct timeval simulator_current_subsec(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return time;
}
static void simulator_lock(struct hj212_client *client)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    pthread_mutex_lock(&this->lock);
}
static int simulator_trylock(struct hj212_client *client)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    return (0 - !!pthread_mutex_trylock(&this->lock));
}
static void simulator_unlock(struct hj212_client *client)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    pthread_mutex_unlock(&this->lock);
}
static void *simulator_malloc(size_t size)
{
    return malloc(size);
}
static void *simulator_calloc(unsigned int num, size_t size)
{
    return calloc(num, size);
}
static void simulator_free(void *ptr)
{
    free(ptr);
}
static int simulator_dev_open(struct hj212_client *client, int flag)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;

    this->isconnect = 1;

    this->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (this->sockfd < 0)
    {
        simulator_free(client);
        HJ_LOG_I("#%d socket: socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) result = %d", this->parent.id, this->sockfd);
        return -1;
    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET; //表示所属地址簇，TCP/IP必须是AF_INET
    // addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addr.sin_addr.S_un.S_addr = inet_addr("192.168.10.78");
    addr.sin_port = htons(12006);

    int result = 0;
    if ((result = connect(this->sockfd, (void *)&addr, sizeof(addr))) < 0)
    {
        HJ_LOG_I("#%d socket: connect(this->sockfd, &addr, sizeof(addr)) result = %d", client->id, result);
        return -1;
    }
    HJ_LOG_I("#%d socket connect succeed", client->id);
    return 0;
}
static int simulator_dev_close(struct hj212_client *client)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;

    this->isconnect = 0;

    HJ_LOG_I("#%d actively disconnect the socket connection", client->id);
    return closesocket(this->sockfd);
}
static int simulator_dev_state(struct hj212_client *client)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    this = this;

    return 0;
}
static int simulator_dev_recv(struct hj212_client *client, uint8_t *buffer, int len, int timeout)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;

    return gen_blk_queue_pop(&this->recvbuffer, buffer, len);
}
static int simulator_dev_send(struct hj212_client *client, const uint8_t *buffer, int len)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;
    int result = send(this->sockfd, (const char *)buffer, len, 0);
    HJ_LOGH_D(buffer, len, "#%d socket send result=%d", client->id, result);

    if (!result && len)
        socket_reset(this);
    return result;
}

static struct hj212_datasource *simulator_get_data_source(struct hj212_client *client, int type)
{
    struct simulator_hj212_client *this = (struct simulator_hj212_client *)client;

    return &this->datasource[type].parent;
}
static struct hj212_datasource *simulator_create_hisdata_source(struct hj212_client *client, int type, time_t begin, time_t end)
{
    struct simulator_time_section_source *source = simulator_malloc(sizeof(struct simulator_time_section_source));
    source->type = type;
    source->client = (struct simulator_hj212_client *)client;
    source->parent.is_empty = simulator_time_section_source_is_empty;
    source->parent.next = simulator_time_section_source_next;

    source->begin = 0;
    source->end = abs((end - begin)) / ((type + 1) * 100);

    source->begin_time = begin;
    source->interval = (type + 1) * 100;

    return &source->parent;
}
static void simulator_delete_data_source(struct hj212_client *client, struct hj212_datasource *source)
{
    simulator_free(source);
}

static int simulator_time_interval_source_is_empty(struct hj212_datasource *source)
{
    struct simulator_time_interval_source *this = (struct simulator_time_interval_source *)source;
    // struct simulator_hj212_client *client = this->client;

    int current = simulator_current_timestamp();
    int time_diff = current - this->last_time;
    if (time_diff >= this->interval) // 超过时间
    {
        return 0;
    }
    else if (time_diff < 0)
    {
        this->last_time = current / this->interval * this->interval;
    }
    return 1;
}
static int simulator_time_interval_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg)
{
    struct simulator_time_interval_source *this = (struct simulator_time_interval_source *)source;
    // struct simulator_hj212_client *client = this->client;

    int current = simulator_current_timestamp();
    int time_diff = current - this->last_time;
    if (time_diff >= this->interval) // 超过时间
    {
        this->last_time = current / this->interval * this->interval;
    }
    else
    {
        if (time_diff < 0)
        {
            this->last_time = current / this->interval * this->interval;
        }
        return -1;
    }
    msg->datatime = current;
    for (int i = 0; i < 13; i++)
    {
        if (this->type == HJ212_MSG_TYPE_RTD)
        {
            struct pol_rtval rtval;
            memset(&rtval, 0, sizeof(rtval));

            rtval.param.codeid = i + 1;
            snprintf(rtval.param.code, HJ212_POLCODE_MAX_LEN, "simulator_%d", i);
            rtval.param.decimal_num = 4;

            rtval.value = i * 100.0 + i * 1.0 + i * 0.01;
            rtval.zs_value = i * 1.0 + i * 0.01;
            if (i < 10)
            {
                rtval.enable_flag = HJ212_ZSRTD_ENABLE;
            }
            memset(&rtval.datamark, 0, sizeof(rtval.datamark));
            snprintf((void *)&rtval.datamark, sizeof(rtval.datamark), "N%d", i);

            gen_blk_queue_push_block(&msg->queue, (void *)&rtval);
        }
        else
        {
            struct pol_his_data hisval;
            memset(&hisval, 0, sizeof(hisval));

            hisval.param.codeid = i + 1;
            snprintf(hisval.param.code, HJ212_POLCODE_MAX_LEN, "simulator_%d", i);
            hisval.param.decimal_num = 4;

            hisval.min = i * 100.0 + i * 1.0 + i * 0.01;
            hisval.avg = hisval.min * 2;
            hisval.max = hisval.min * 3;
            hisval.cou = hisval.min * 5;

            hisval.zs_min = i * 100.0 + i * 1.0 + i * 0.01;
            hisval.zs_avg = hisval.zs_min * 2;
            hisval.zs_max = hisval.zs_min * 3;

            if (i < 5)
            {
                hisval.enable_flag = HJ212_ZSHIS_ENABLE | HJ212_COU_ENABLE | HJ212_HISFLAG_ENABLE;
            }
            if (i >= 5 && i < 10)
            {
                hisval.enable_flag = HJ212_COU_ENABLE | HJ212_HISFLAG_ENABLE;
            }
            if (i >= 10)
            {
                hisval.enable_flag = HJ212_HISFLAG_ENABLE;
            }
            memset(&hisval.datamark, 0, sizeof(hisval.datamark));
            snprintf((void *)&hisval.datamark, sizeof(hisval.datamark), "N%d", i);

            gen_blk_queue_push_block(&msg->queue, (void *)&hisval);
        }
    }
    return 0;
}


static int simulator_time_section_source_is_empty(struct hj212_datasource *source)
{
    struct simulator_time_section_source *this = (struct simulator_time_section_source *)source;
    return this->begin > this->end;
}
static int simulator_time_section_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg)
{
    struct simulator_time_section_source *this = (struct simulator_time_section_source *)source;
    if (this->begin > this->end)
    {
        return -1;
    }
    msg->datatime = this->begin_time + this->begin * this->interval;
    this->begin++;
    for (int i = 0; i < 13; i++)
    {
        if (this->type == HJ212_MSG_TYPE_RTD)
        {
            struct pol_rtval rtval;
            memset(&rtval, 0, sizeof(rtval));

            rtval.param.codeid = i + 1;
            snprintf(rtval.param.code, HJ212_POLCODE_MAX_LEN, "simulator_%d", i);
            rtval.param.decimal_num = 4;

            rtval.value = i * 100.0 + i * 1.0 + i * 0.01;
            rtval.zs_value = i * 1.0 + i * 0.01;
            if (i < 10)
            {
                rtval.enable_flag = HJ212_ZSRTD_ENABLE;
            }
            memset(&rtval.datamark, 0, sizeof(rtval.datamark));
            snprintf((void *)&rtval.datamark, sizeof(rtval.datamark), "N%d", i);

            gen_blk_queue_push_block(&msg->queue, (void *)&rtval);
        }
        else
        {
            struct pol_his_data hisval;
            memset(&hisval, 0, sizeof(hisval));

            hisval.param.codeid = i + 1;
            snprintf(hisval.param.code, HJ212_POLCODE_MAX_LEN, "simulator_%d", i);
            hisval.param.decimal_num = 4;

            hisval.min = i * 100.0 + i * 1.0 + i * 0.01;
            hisval.avg = hisval.min * 2;
            hisval.max = hisval.min * 3;
            hisval.cou = hisval.min * 5;

            hisval.zs_min = i * 100.0 + i * 1.0 + i * 0.01;
            hisval.zs_avg = hisval.zs_min * 2;
            hisval.zs_max = hisval.zs_min * 3;

            if (i < 5)
            {
                hisval.enable_flag = HJ212_ZSHIS_ENABLE | HJ212_COU_ENABLE | HJ212_HISFLAG_ENABLE;
            }
            if (i >= 5 && i < 10)
            {
                hisval.enable_flag = HJ212_COU_ENABLE | HJ212_HISFLAG_ENABLE;
            }
            if (i >= 10)
            {
                hisval.enable_flag = HJ212_HISFLAG_ENABLE;
            }
            memset(&hisval.datamark, 0, sizeof(hisval.datamark));
            snprintf((void *)&hisval.datamark, sizeof(hisval.datamark), "N%d", i);

            gen_blk_queue_push_block(&msg->queue, (void *)&hisval);
        }
    }
    return 0;
}
















